#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/mmc/dw_mmc.h>
#include <linux/clk.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
#include <linux/phy.h>
#include <linux/dma-mapping.h>
#include <linux/spi/eeprom.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/if_alg.h>
#include <linux/mmc/host.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <mach/pmu.h>
#include <mach/io.h>
#include <mach/board_config.h>
#include <mach/pinctrl.h>
#include <mach/clock.h>
#include <mach/fh_uart_plat.h>
#include <mach/fh_mci_plat.h>
#include <mach/fh_mshc_plat.h>
#include <mach/fh_gmac_plat.h>
#include <mach/fh_gpio_plat.h>
#include <mach/mol_efuse_plat.h>
#include <mach/fh_dma_plat.h>
#include <mach/fh_spi_plat.h>
#include <mach/fh_i2s_plat.h>
#include <mach/fh_pwm_plat.h>
#include <mach/fh_wdt_plat.h>
#include <mach/fh_usb_plat.h>
#include <mach/fh_sadc_plat.h>
#include <mach/fh_rtc_plat.h>
#include <mach/fh_cesa_plat.h>
#include <mach/platsmp.h>
#include "chip.h"
#include "../soc.h"
#include <linux/gpio.h>
#include <linux/irqchip/arm-gic.h>
#include "linux/pwm_backlight.h"
#include "lp.h"


#define CONFIG_GPIO_EMAC_0_PHY_RESET    (128)
#define CONFIG_GPIO_EMAC_1_PHY_RESET    (128)

struct uart_port fh_serial_ports[FH_UART_NUMBER];
static void *va_ephy;
static struct map_desc qm102v_io_desc[] = {
	{
		.virtual	= VA_CPU_SYS_AHB_REG_BASE,
		.pfn		= __phys_to_pfn(CPU_SYS_AHB_REG_BASE),
		.length		= SZ_16K,
		.type		= MT_DEVICE,
	},

	{
		.virtual	= VA_TOP_PRE_DIV_RF_REG_BASE,
		.pfn		= __phys_to_pfn(TOP_PRE_DIV_RF_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_CEN_GLB_APB_REG_BASE,
		.pfn		= __phys_to_pfn(CEN_GLB_APB_REG_BASE),
		.length		= SZ_16K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_DMC_SYS_APB_REG_BASE,
		.pfn		= __phys_to_pfn(DMC_SYS_APB_REG_BASE),
		.length		= SZ_16K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_ISP_SYS_APB_REG_BASE,
		.pfn		= __phys_to_pfn(ISP_SYS_APB_REG_BASE),
		.length		= SZ_16K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_CEN_PIN_REG_BASE,
		.pfn		= __phys_to_pfn(CEN_PIN_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_VEU_SYS_PIN_REG_BASE,
		.pfn		= __phys_to_pfn(VEU_SYS_PIN_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_ISP_SYS_PIN_REG_BASE,
		.pfn		= __phys_to_pfn(ISP_SYS_PIN_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_CSI_SYS_PIN_REG_BASE,
		.pfn		= __phys_to_pfn(CSI_SYS_PIN_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_CPU_SYS_PIN_REG_BASE,
		.pfn		= __phys_to_pfn(CPU_SYS_PIN_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_UART0_REG_BASE,
		.pfn		= __phys_to_pfn(UART0_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_UART1_REG_BASE,
		.pfn		= __phys_to_pfn(UART1_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_PTS_REG_BASE,
		.pfn		= __phys_to_pfn(PTS_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_CPU_SYS_CLK_RF_PRE_REG_BASE,
		.pfn		= __phys_to_pfn(CPU_SYS_CLK_RF_PRE_REG_BASE),
		.length		= SZ_16K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_VEU_SYS_AHB_REG_BASE,
		.pfn		= __phys_to_pfn(VEU_SYS_AHB_REG_BASE),
		.length		= SZ_16K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_PMU_CFG_REG_BASE,
		.pfn		= __phys_to_pfn(PMU_CFG_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
};

static struct resource fh_gpio0_resources[] = {
	{
		.start		= GPIO0_REG_BASE,
		.end		= GPIO0_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= GPIO0_IRQ,
		.end		= GPIO0_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_gpio1_resources[] = {
	{
		.start		= GPIO1_REG_BASE,
		.end		= GPIO1_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= GPIO1_IRQ,
		.end		= GPIO1_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_gpio2_resources[] = {
	{
		.start		= GPIO2_REG_BASE,
		.end		= GPIO2_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= GPIO2_IRQ,
		.end		= GPIO2_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_gpio3_resources[] = {
	{
		.start		= GPIO3_REG_BASE,
		.end		= GPIO3_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= GPIO3_IRQ,
		.end		= GPIO3_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_gpio4_resources[] = {
	{
		.start		= GPIO4_REG_BASE,
		.end		= GPIO4_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= GPIO4_IRQ,
		.end		= GPIO4_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_gpio5_resources[] = {
	{
		.start		= GPIO5_REG_BASE,
		.end		= GPIO5_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= GPIO5_IRQ,
		.end		= GPIO5_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_gpio6_resources[] = {
	{
		.start		= GPIO6_REG_BASE,
		.end		= GPIO6_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= GPIO6_IRQ,
		.end		= GPIO6_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_uart0_resources[] = {
	{
		.start		= (UART0_REG_BASE),
		.end		= (UART0_REG_BASE) + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= UART0_IRQ,
		.end		= UART0_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_uart1_resources[] = {
	{
		.start		= (UART1_REG_BASE),
		.end		= (UART1_REG_BASE) + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= UART1_IRQ,
		.end		= UART1_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_uart2_resources[] = {
	{
		.start		= (UART2_REG_BASE),
		.end		= (UART2_REG_BASE) + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= UART2_IRQ,
		.end		= UART2_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_spi0_resources[] = {
	{
		.start		= SPI0_REG_BASE,
		.end		= SPI0_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= SPI0_IRQ,
		.end		= SPI0_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_spi1_resources[] = {
	{
		.start		= SPI1_REG_BASE,
		.end		= SPI1_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= SPI1_IRQ,
		.end		= SPI1_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_gmac_qos_0_resources[] = {
	{
		.start		= GMAC0_REG_BASE,
		.end		= GMAC0_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= GMAC0_SBD_INTR_IRQ,
		.end		= GMAC0_SBD_INTR_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_wdt0_resources[] = {
	{
		.start		= WDT0_REG_BASE,
		.end		= WDT0_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= WDT0_IRQ,
		.end		= WDT0_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_pwm_resources[] = {
	{
		.start		= PWM_REG_BASE,
		.end		= PWM_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= PWM_IRQ,
		.end		= PWM_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_i2c_resources_0[] = {
	{
		.start		= I2C0_REG_BASE,
		.end		= I2C0_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= I2C0_IRQ,
		.end		= I2C0_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_i2c_resources_1[] = {
	{
		.start		= I2C1_REG_BASE,
		.end		= I2C1_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= I2C1_IRQ,
		.end		= I2C1_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_rtc_resources[] = {
	{
		.start		= RTC_REG_BASE,
		.end		= RTC_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= RTC_IRQ,
		.end		= RTC_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

#ifdef CONFIG_FH_RSA
static struct resource fh_rsa_resources[] = {
	{
		.start		= RSA_REG_BASE,
		.end		= RSA_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= RSA_IRQ,
		.end		= RSA_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};
#endif

#ifdef CONFIG_HW_RANDOM_FH
/*
 *static struct resource fh_rng_resources[] = {
 *	{
 *		.start		= RNG_REG_BASE,
 *		.end		= RNG_REG_BASE + SZ_1M - 1,
 *		.flags		= IORESOURCE_MEM,
 *	},
 *	{
 *		.start		= RNG_IRQ,
 *		.end		= RNG_IRQ,
 *		.flags		= IORESOURCE_IRQ,
 *	},
 *};
 */
#endif

static struct resource fh_usb_resources[] = {
	{
		.start		= USBC_REG_BASE,
		.end		= USBC_REG_BASE + SZ_1M - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= USBC_IRQ,
		.end		= USBC_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_sdc0_resources[] = {
	{
		.start		= SDIO0_REG_BASE,
		.end		= SDIO0_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= SDIO0_IRQ,
		.end		= SDIO0_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_sdc1_resources[] = {
	{
		.start		= SDIO1_REG_BASE,
		.end		= SDIO1_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= SDIO1_IRQ,
		.end		= SDIO1_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

#ifdef CONFIG_FH_STEPMOTOR
static struct resource fh_stepmotor_resources0[] = {
	{
		.start		= STM0_REG_BASE,
		.end		= STM0_REG_BASE + SZ_4K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= STM0_IRQ,
		.end		= STM0_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_stepmotor_resources1[] = {
	{
		.start		= STM1_REG_BASE,
		.end		= STM1_REG_BASE + SZ_4K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= STM1_IRQ,
		.end		= STM1_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

#endif

static struct resource fh_sadc_resources[] = {
	{
		.start		= SADC_REG_BASE,
		.end		= SADC_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= SADC_IRQ,
		.end		= SADC_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

struct fh_sadc_platform_data fh_sadc_data = {
	.ref_vol = 1800,
	.active_bit = 0xfff,
};

static struct platform_device fh_sadc_device = {
	.name			= "fh_sadc",
	.id			= 0,
	.num_resources		= ARRAY_SIZE(fh_sadc_resources),
	.resource		= fh_sadc_resources,
	.dev			= {
	.platform_data = &fh_sadc_data,
	},
};

static struct fh_uart_dma uart1_dma_info = {
#ifdef CONFIG_UART_TX_DMA
	.tx_hs_no       = UART1_TX_HW_HANDSHAKE,
	.tx_dma_channel = UART1_DMA_TX_CHAN,
#endif
	.rx_hs_no       = UART1_RX_HW_HANDSHAKE,
	.rx_dma_channel = UART1_DMA_RX_CHAN,
	.rx_xmit_len    = 64,
};

static struct fh_uart_dma uart2_dma_info = {
#ifdef CONFIG_UART_TX_DMA
	.tx_hs_no       = UART2_TX_HW_HANDSHAKE,
	.tx_dma_channel = UART2_DMA_TX_CHAN,
#endif
	.rx_hs_no       = UART2_RX_HW_HANDSHAKE,
	.rx_dma_channel = UART2_DMA_RX_CHAN,
	.rx_xmit_len    = 64,
};

static struct fh_platform_uart fh_uart_platform_data[] = {
	{
		.mapbase	= UART0_REG_BASE,
		.fifo_size	= 256,
		.irq		= UART0_IRQ,
		.uartclk	= 24000000,
	},
	{
		.mapbase	= UART1_REG_BASE,
		.fifo_size	= 256,
		.irq		= UART1_IRQ,
		.uartclk	= 24000000,
		.use_dma	= 0,
		.dma_info	= &uart1_dma_info,
	},
	{
		.mapbase	= UART2_REG_BASE,
		.fifo_size	= 256,
		.irq		= UART2_IRQ,
		.uartclk	= 24000000,
		.use_dma	= 0,
		.dma_info	= &uart2_dma_info,
		.flags		= UPF_HARD_FLOW,
	},
};



struct phy_reg_cfg phy_config_array[] = {
	{
		.id = FH_GMAC_PHY_RTL8201,
		.list = {
			{W_PHY, 0x1f, 0x7},
			{W_PHY, 0x10, 0x1ff4},
			{W_PHY, 0x1f, 0},
			{W_PHY, 0x0d, 0x07},
			{W_PHY, 0x0e, 0x3c},
			{W_PHY, 0x0d, 0x4007},
			{W_PHY, 0x0e, 0x0},
			{0},
		},
		.inf_sup = PHY_INTERFACE_MODE_MII,
	},
	{
		.id = FH_GMAC_PHY_IP101G,
		.list = {
			{W_PHY, 0x14, 0x10},
			{W_PHY, 0x10, 0x1006},
			{W_PHY, 0x14, 0x10},
			{0},
		},
		.inf_sup = PHY_INTERFACE_MODE_RMII,
	},
	{
		.id = FH_GMAC_PHY_TI83848,
		.list = {
			{M_PHY, 0x11, 0x20, 0x20},
			{0},
		},
		.inf_sup = PHY_INTERFACE_MODE_RMII,
	},
	{
		.id = FH_GMAC_PHY_DUMMY,
		.list = {
			{0},
		},
		.inf_sup = PHY_INTERFACE_MODE_RMII,
	},
	{
		.id = FH_GMAC_PHY_INTERNAL_V2,
		.list = {
			{0},
		},
		.inf_sup = PHY_INTERFACE_MODE_MII,
	},
	{0},
};

static int phy_0_inf_set(unsigned int inf)
{
	return 0;
}


static int eth_0_set_speed(unsigned int speed, void *pri)
{
	return 0;
}


static int phy_0_sel_func(unsigned int phy_sel)
{
	return 0;
}

enum {
	CP_VAL_0,
	CP_VAL_1,
	VAL_100M_0,
	VAL_100M_1,
	VAL_10M_0,
	VAL_10M_1,
	TRAIN_MAX_SIZE,
};

static u32 train_100_array[] = {
	31, 30, 29, 28,
	27, 26, 25, 24,
	23, 22, 21, 20,
	19, 18, 17, 16,
	0,  1,  2,  3,
	4,  5,  6,  7,
	8,  9,  10, 11,
	12, 13, 14, 15,
};

static u32 train_10_array[] = {
	31, 30, 29, 28,
	27, 26, 25, 24,
	23, 22, 21, 20,
	19, 18, 17, 16,
	0,  1,  2,  3,
	4,  5,  6,  7,
	8,  9,  10, 11,
	12, 13, 14, 15,
};

static u32 train_cp_array[] = {
	0, 1, 2, 3,
};
#define REFIX_CP_TRAIN_DATA_OFFSET	    (0)
#define REFIX_100M_TRAIN_DATA_OFFSET    (0)
#define REFIX_10M_TRAIN_DATA_OFFSET	    (0)

struct s_train_val train_array[TRAIN_MAX_SIZE] = {

		[CP_VAL_0].name = "cp_val_0",
		[CP_VAL_0].src_add = REG_PMU_EPHY_PARAM,
		[CP_VAL_0].src_mask = 0xc0,
		[CP_VAL_0].src_vaild_index = 15,
		[CP_VAL_0].dst_add = 0x18,
		[CP_VAL_0].dst_vaild_index = 22,
		[CP_VAL_0].bind_train_array = train_cp_array,
		[CP_VAL_0].bind_train_size = ARRAY_SIZE(train_cp_array),
		[CP_VAL_0].usr_train_offset =
		REFIX_CP_TRAIN_DATA_OFFSET,

		[CP_VAL_1].name = "cp_val_1",
		[CP_VAL_1].src_add = REG_PMU_EPHY_PARAM,
		[CP_VAL_1].src_mask = 0xc0,
		[CP_VAL_1].src_vaild_index = 15,
		[CP_VAL_1].dst_add = 0xb7c,
		[CP_VAL_1].dst_vaild_index = 6,
		[CP_VAL_1].bind_train_array = train_cp_array,
		[CP_VAL_1].bind_train_size = ARRAY_SIZE(train_cp_array),
		[CP_VAL_1].usr_train_offset =
		REFIX_CP_TRAIN_DATA_OFFSET,

		[VAL_100M_0].name = "val_100M_0",
		[VAL_100M_0].src_add = REG_PMU_EPHY_PARAM,
		[VAL_100M_0].src_mask = 0x1f,
		[VAL_100M_0].src_vaild_index = 5,
		[VAL_100M_0].dst_add = 0x24,
		[VAL_100M_0].dst_vaild_index = 8,
		[VAL_100M_0].bind_train_array = train_100_array,
		[VAL_100M_0].bind_train_size = ARRAY_SIZE(train_100_array),
		[VAL_100M_0].usr_train_offset =
		REFIX_100M_TRAIN_DATA_OFFSET,

		[VAL_100M_1].name = "val_100M_1",
		[VAL_100M_1].src_add = REG_PMU_EPHY_PARAM,
		[VAL_100M_1].src_mask = 0x1f,
		[VAL_100M_1].src_vaild_index = 5,
		[VAL_100M_1].dst_add = 0x1308,
		[VAL_100M_1].dst_vaild_index = 8,
		[VAL_100M_1].bind_train_array = train_100_array,
		[VAL_100M_1].bind_train_size = ARRAY_SIZE(train_100_array),
		[VAL_100M_1].usr_train_offset =
		REFIX_100M_TRAIN_DATA_OFFSET,

		[VAL_10M_0].name = "val_10M_0",
		[VAL_10M_0].src_add = REG_PMU_EPHY_PARAM,
		[VAL_10M_0].src_mask = 0x1f00,
		[VAL_10M_0].src_vaild_index = 13,
		[VAL_10M_0].dst_add = 0x24,
		[VAL_10M_0].dst_vaild_index = 16,
		[VAL_10M_0].bind_train_array = train_10_array,
		[VAL_10M_0].bind_train_size = ARRAY_SIZE(train_10_array),
		[VAL_10M_0].usr_train_offset =
		REFIX_10M_TRAIN_DATA_OFFSET,

		[VAL_10M_1].name = "val_10M_1",
		[VAL_10M_1].src_add = REG_PMU_EPHY_PARAM,
		[VAL_10M_1].src_mask = 0x1f00,
		[VAL_10M_1].src_vaild_index = 13,
		[VAL_10M_1].dst_add = 0x1308,
		[VAL_10M_1].dst_vaild_index = 0,
		[VAL_10M_1].bind_train_array = train_10_array,
		[VAL_10M_1].bind_train_size = ARRAY_SIZE(train_10_array),
		[VAL_10M_1].usr_train_offset =
		REFIX_10M_TRAIN_DATA_OFFSET,
};

void dump_phy_train_val(struct s_train_val *p_train)
{
	pr_err("------------GAP_LINE---------------\n");
	pr_err("name            : %s\n", p_train->name);
	pr_err("src_add         : %08x\n", p_train->src_add);
	pr_err("src_mask        : %08x\n", p_train->src_mask);
	pr_err("src_vaild_index : %08x\n", p_train->src_vaild_index);
	pr_err("dst_add         : %08x\n", p_train->dst_add);
	pr_err("dst_vaild_index : %08x\n", p_train->dst_vaild_index);
	pr_err("usr_train_offset: %d\n", p_train->usr_train_offset);
}


void parse_train_data(struct s_train_val *p_train)
{
	unsigned long test_data;
	int i;
	u32 temp_data;
	u32 vaild_bit_pos;
	int max_offset, low_offset;
	u32 *array;
	u32 size;

	if (!va_ephy) {
		pr_err("ioremap internal phy err\n");
		BUG_ON(1);
	}

	array = p_train->bind_train_array;
	size = p_train->bind_train_size;
	test_data = p_train->src_mask;
	vaild_bit_pos = find_first_bit(&test_data, 32);

	if ((!array) ||
	((p_train->src_mask >> vaild_bit_pos) != (size - 1))) {
		pr_err("para error..\n");
		return;
	}

	temp_data = fh_pmu_get_reg(p_train->src_add);
	if (temp_data & (1 << p_train->src_vaild_index)) {
		/*got vaild val*/
		temp_data &= p_train->src_mask;
		temp_data >>= vaild_bit_pos;
		pr_err("[%s] :: train val %d\n", p_train->name, temp_data);
		/*find index*/
		for (i = 0; i < size; i++) {
			if (temp_data == array[i]) {
				max_offset = (size - 1) - i;
				low_offset = 0 - i;
				break;
			}
		}

		if ((p_train->usr_train_offset < low_offset) ||
		(p_train->usr_train_offset > max_offset)) {
			pr_err("offset [%d] should limit in [%d , %d]\n",
			p_train->usr_train_offset, low_offset, max_offset);
			return;
		}
		//fix array idx..
		i += p_train->usr_train_offset;
		temp_data = array[i];
		/*pr_err("fix idx :: [%d] = %d\n", i, temp_data);*/
	} else {
		temp_data = 0;
		pr_err("[%s] :: use default train data %d\n",
		p_train->name, temp_data);
	}
	temp_data &= (p_train->src_mask >> vaild_bit_pos);
	SET_REG_M((u32)va_ephy + p_train->dst_add,
	temp_data << p_train->dst_vaild_index,
	(p_train->src_mask >> vaild_bit_pos) << p_train->dst_vaild_index);
}


static void fh_internal_phy_reset(void)
{
	int idx;

	/*just map once*/
	if (!va_ephy)
		va_ephy = ioremap(EPHY_REG_BASE, SZ_16K);

	if (!va_ephy) {
		pr_err("ioremap internal phy err\n");
		BUG_ON(1);
	}

	pr_err("fh internal phy reset go...\n ");

	fh_pmu_set_reg(REG_EPHY_CTRL0, 0xc);

	SET_REG_M((u32)va_ephy + 0, 0, 0x3<<7);
	SET_REG((u32)va_ephy + 0x28, 0x00247875);
	SET_REG((u32)va_ephy + 0x1274, 0x3c3);

	fh_pmu_set_reg_m(REG_GMAC_CTRL0, 1<<4, 1<<4); // ephy soft reset
	fh_pmu_set_reg_m(REG_EPHY_CTRL0, 1<<4, 1<<4); // apb ephy soft reset
	udelay(200);
	fh_pmu_set_reg_m(REG_EPHY_CTRL0, 0, 1<<4);
	fh_pmu_set_reg_m(REG_GMAC_CTRL0, 0, 1<<4);

	SET_REG_M((u32)va_ephy + 0x1370, 0x0, 1<<3);
	SET_REG((u32)va_ephy + 0x1274, 0x3c3);
	SET_REG((u32)va_ephy + 0x0b6C, 0xf04);
	SET_REG((u32)va_ephy + 0x1340, 0x0000);
	SET_REG((u32)va_ephy + 0x0bA8, 0x20);
	SET_REG((u32)va_ephy + 0x0018, 0x00c02800);
	SET_REG((u32)va_ephy + 0x001c, 0x00810000);
	SET_REG((u32)va_ephy + 0x0020, 0x0000340c);
	SET_REG((u32)va_ephy + 0x0024, 0x30131500);
	SET_REG((u32)va_ephy + 0x0028, 0x01402800);
	SET_REG((u32)va_ephy + 0x001c, 0xa1800000);
	SET_REG((u32)va_ephy + 0x0028, 0x00402800);
	SET_REG((u32)va_ephy + 0x0014, 0x06000000);
	SET_REG((u32)va_ephy + 0x0020, 0x2340c);
	SET_REG((u32)va_ephy + 0x000c, 0xba0edfff);
	SET_REG((u32)va_ephy + 0x0010, 0x7fcbf9de);
	SET_REG((u32)va_ephy + 0x0b98, 0xd150);
	SET_REG((u32)va_ephy + 0x1224, 0);
	SET_REG((u32)va_ephy + 0x12f0, 0);
	SET_REG((u32)va_ephy + 0x0bc0, 0x7de);
	SET_REG((u32)va_ephy + 0x0bc8, 0x09de);
	SET_REG((u32)va_ephy + 0x070c, 0x0401);
	SET_REG((u32)va_ephy + 0x0a84, 0x1d20);
	SET_REG((u32)va_ephy + 0x06d4, 0x3130);
	SET_REG((u32)va_ephy + 0x0a6c, 0x0818);
	SET_REG((u32)va_ephy + 0x0aec, 0x1000);
	SET_REG((u32)va_ephy + 0x0658, 0x1c00);
	SET_REG((u32)va_ephy + 0x07d4, 0x6900);
	SET_REG((u32)va_ephy + 0x06b8, 0x4);
	SET_REG((u32)va_ephy + 0x06E4, 0x04a0);
	SET_REG((u32)va_ephy + 0x0BBC, 0x1759);
	SET_REG((u32)va_ephy + 0x0bf8, 0x0100);
	SET_REG((u32)va_ephy + 0x0794, 0x9000);
	SET_REG((u32)va_ephy + 0x0788, 0xf);
	SET_REG((u32)va_ephy + 0x1378, 0x2338);
	SET_REG_M((u32)va_ephy + 0x0, 0x20<<24, 0xff<<24);
	SET_REG_M((u32)va_ephy + 0x4, 0x18, 0xff);
	SET_REG((u32)va_ephy + 0x0680, 0x0552);
	SET_REG((u32)va_ephy + 0x1274, 0);
	SET_REG((u32)va_ephy + 0x0b6C, 0x704);
	SET_REG((u32)va_ephy + 0x1340, 0);
	SET_REG((u32)va_ephy + 0x0ba8, 0);
	SET_REG((u32)va_ephy + 0x06c8, 0xc000);
	SET_REG((u32)va_ephy + 0x06e0, 0x8508);
	SET_REG((u32)va_ephy + 0x1328, 0x0065);
	SET_REG((u32)va_ephy + 0x076c, 0x0430);
	SET_REG((u32)va_ephy + 0x06b4, 0xfd00);
	SET_REG((u32)va_ephy + 0x1360, 0x3f37);
	SET_REG_M((u32)va_ephy + 0x0778, 0x24 << 8, 0xff << 8);
	SET_REG_M((u32)va_ephy + 0x077c, 0x24, 0xff);
	SET_REG((u32)va_ephy + 0xb10, 0x5000);
	SET_REG((u32)va_ephy + 0xb14, 0x8000);
	SET_REG((u32)va_ephy + 0xb1c, 0x000e);
	SET_REG((u32)va_ephy + 0xb20, 0x000e);
	SET_REG((u32)va_ephy + 0xb1c, 0x000f);
	SET_REG((u32)va_ephy + 0xb20, 0x0035);
	SET_REG((u32)va_ephy + 0xb1c, 0x0000);
	SET_REG((u32)va_ephy + 0xb10, 0x0000);
	SET_REG((u32)va_ephy + 0xb14, 0x0000);
	/*led*/
	SET_REG((u32)va_ephy + 0x7ec, 0x8a6);
	SET_REG((u32)va_ephy + 0x2c, 0x10);
	SET_REG((u32)va_ephy + 0x07f8, 0x325);

	for (idx = 0; idx < ARRAY_SIZE(train_array); idx++) {
		/*dump_phy_train_val(&train_array[idx]);*/
		parse_train_data(&train_array[idx]);
	}
}


static void fh_internal_phy_link_up_cb(void *pri)
{

	if (!va_ephy) {
		pr_err("ioremap internal phy err\n");
		BUG_ON(1);
	}

	SET_REG((u32)va_ephy + 0x0b10, 0x5000);
	SET_REG((u32)va_ephy + 0x0b14, 0x8000);
	SET_REG((u32)va_ephy + 0x0b1c, 0x000e);
	SET_REG((u32)va_ephy + 0x0b20, 0x0004);
	SET_REG((u32)va_ephy + 0x0aec, 0x1800);
	SET_REG((u32)va_ephy + 0x0b10, 0x0000);
	SET_REG((u32)va_ephy + 0x0b14, 0x0000);

}

static void fh_internal_phy_link_down_cb(void *pri)
{
	if (!va_ephy) {
		pr_err("ioremap internal phy err\n");
		BUG_ON(1);
	}

	SET_REG((u32)va_ephy + 0xb10, 0x5000);
	SET_REG((u32)va_ephy + 0xb14, 0x8000);
	SET_REG((u32)va_ephy + 0xb1c, 0x000e);
	SET_REG((u32)va_ephy + 0xb20, 0x000e);
	SET_REG((u32)va_ephy + 0xb1c, 0x000f);
	SET_REG((u32)va_ephy + 0xb20, 0x0035);
	SET_REG((u32)va_ephy + 0xb1c, 0x0000);
	SET_REG((u32)va_ephy + 0xb10, 0x0000);
	SET_REG((u32)va_ephy + 0xb14, 0x0000);
}


static struct fh_gmac_platform_data fh_gmac0_plat_data = {
	.phy_sel = phy_0_sel_func,
	.inf_set = phy_0_inf_set,
	.gmac_reset = 0,
	.p_cfg_array = phy_config_array,
	.phy_info[0] = {
		.phy_sel = INTERNAL_PHY,
		.phy_inf = PHY_INTERFACE_MODE_MII,
		.phy_reset = fh_internal_phy_reset,
		.ex_sync_mac_spd = 0,
		.brd_link_up_cb = fh_internal_phy_link_up_cb,
		.brd_link_down_cb = fh_internal_phy_link_down_cb,
	},

};


static struct platform_device fh_gmac_qos_0_device = {
	.name           = "fh_qos_gmac",
	.id             = 0,
	.num_resources  = ARRAY_SIZE(fh_gmac_qos_0_resources),
	.resource       = fh_gmac_qos_0_resources,
	.dev = {
		.coherent_dma_mask = DMA_BIT_MASK(32),
		.platform_data = &fh_gmac0_plat_data,
	},
};

static struct fh_gpio_chip fh_gpio0_chip = {
	.chip = {
		.owner = THIS_MODULE,
		.label = "FH_GPIO0",
		.base = 0,
		.ngpio = 8,
	},
};

static struct fh_gpio_chip fh_gpio1_chip = {
	.chip = {
		.owner = THIS_MODULE,
		.label = "FH_GPIO1",
		.base = 8,
		.ngpio = 8,
	},
};

static struct fh_gpio_chip fh_gpio2_chip = {
	.chip = {
		.owner = THIS_MODULE,
		.label = "FH_GPIO2",
		.base = 16,
		.ngpio = 8,
	},
};

static struct fh_gpio_chip fh_gpio3_chip = {
	.chip = {
		.owner = THIS_MODULE,
		.label = "FH_GPIO3",
		.base = 24,
		.ngpio = 8,
	},
};

static struct fh_gpio_chip fh_gpio4_chip = {
	.chip = {
		.owner = THIS_MODULE,
		.label = "FH_GPIO4",
		.base = 32,
		.ngpio = 8,
	},
};

static struct fh_gpio_chip fh_gpio5_chip = {
	.chip = {
		.owner = THIS_MODULE,
		.label = "FH_GPIO5",
		.base = 40,
		.ngpio = 8,
	},
};

static struct fh_gpio_chip fh_gpio6_chip = {
	.chip = {
		.owner = THIS_MODULE,
		.label = "FH_GPIO6",
		.base = 48,
		.ngpio = 8,
	},
};


int fh_mci_sys_init(unsigned int slot_id, void *irq_handler_t, void *para)
{
	unsigned int reg;

	if (slot_id == 1) {
		/*clk gate*/
		reg = readl(CK_CTRL2);
		reg |= (0x1 << 9 | 0x1 << 8 | 0x1 << 17);
		writel(reg, CK_CTRL2);

		/*sel clk 50M*/
		reg = readl(CK_CTRL2);
		reg &= ~(0x1 << 3);
		reg |= 0x1 << 3;
		writel(reg, CK_CTRL2);

		/*config dll*/
		writel(0x758, SDIO1_CTRL0);
		writel(0x9, SDIO1_DLLININFOREG_SPL);
		/*rst sdio*/
		reg = readl(SDIO1_CTRL1);
		reg |= 0x1 << 27;
		udelay(1000);
		writel(reg, SDIO1_CTRL1);
		reg &= ~(0x1 << 27);
		udelay(1000);
		writel(reg, SDIO1_CTRL1);
	} else {
		/*clk gate*/
		reg = readl(CK_CTRL2);
		reg |= (0x1 << 25 | 0x1 << 24 | 0x1 << 18);
		writel(reg, CK_CTRL2);

		/*sel clk 50M*/
		reg = readl(CK_CTRL2);
		reg &= ~(0x1 << 4);
		reg |= 0x1 << 4;
		writel(reg, CK_CTRL2);
		/*config dll*/

		writel(0x758, SDIO0_CTRL0);
		writel(0x9, SDIO0_DLLININFOREG_SPL);
		/*rst sdio*/
		reg = readl(SDIO0_CTRL1);
		reg |= 0x1 << 27;
		udelay(1000);
		writel(reg, SDIO0_CTRL1);
		reg &= ~(0x1 << 27);
		udelay(1000);
		writel(reg, SDIO0_CTRL1);
	}
	return 0;
}

static unsigned int  fh_mci_sys_card_detect_fixed(struct fhmci_host *host)
{
	return 0;
}

struct fh_mci_board fh_mci = {
	.num_slots = 1,
	.get_cd = fh_mci_sys_card_detect_fixed,
	.bus_hz = 50000000,
	.detect_delay_ms = 200,
	.caps = MMC_CAP_4_BIT_DATA,
	/*8:180  degree*/
	.drv_degree = 4,
	.sam_degree = 0,
	.init = fh_mci_sys_init,//add this for wifi
	.rescan_max_num = 2,
};

struct fh_mci_board fh_mci_sd = {
	.num_slots = 1,
	.bus_hz = 50000000,
	.detect_delay_ms = 200,
	.caps = MMC_CAP_4_BIT_DATA,
	/*8:180  degree*/
	.drv_degree = 8,
	.sam_degree = 0,
	.init = fh_mci_sys_init,
	.rescan_max_num = 0,
};

struct platform_device fh_sd0_device = {
	.name			= "fh_mci",
	.id			= 0,
	.num_resources		= ARRAY_SIZE(fh_sdc0_resources),
	.resource		= fh_sdc0_resources,
	.dev			= {
	.coherent_dma_mask	= DMA_BIT_MASK(32),
	.platform_data = &fh_mci_sd,
	}
};

struct platform_device fh_sd1_device = {
	.name			= "fh_mci",
	.id			= 1,
	.num_resources		= ARRAY_SIZE(fh_sdc1_resources),
	.resource		= fh_sdc1_resources,
	.dev			= {
	.coherent_dma_mask	= DMA_BIT_MASK(32),
	//.platform_data		= &fh_mci_sd,// chg this as following for wifi
	.platform_data		= &fh_mci,
	}
};

static struct platform_device fh_uart0_device = {
	.name				= "ttyS",
	.id					= 0,
	.num_resources		= ARRAY_SIZE(fh_uart0_resources),
	.resource			= fh_uart0_resources,
	.dev.platform_data	= &fh_uart_platform_data[0],
};

static struct platform_device fh_uart1_device = {
	.name				= "ttyS",
	.id					= 1,
	.num_resources		= ARRAY_SIZE(fh_uart1_resources),
	.resource			= fh_uart1_resources,
	.dev.platform_data	= &fh_uart_platform_data[1],
};

static struct platform_device fh_uart2_device = {
	.name				= "ttyS",
	.id					= 2,
	.num_resources		= ARRAY_SIZE(fh_uart2_resources),
	.resource			= fh_uart2_resources,
	.dev.platform_data	= &fh_uart_platform_data[2],
};


static struct platform_device fh_gpio0_device = {
	.name			= GPIO_NAME,
	.id				= 0,
	.num_resources	= ARRAY_SIZE(fh_gpio0_resources),
	.resource		= fh_gpio0_resources,
	.dev			= {
		.platform_data = &fh_gpio0_chip,
	},
};

static struct platform_device fh_gpio1_device = {
	.name			= GPIO_NAME,
	.id				= 1,
	.num_resources	= ARRAY_SIZE(fh_gpio1_resources),
	.resource		= fh_gpio1_resources,
	.dev			= {
		.platform_data = &fh_gpio1_chip,
	},
};

static struct platform_device fh_gpio2_device = {
	.name			= GPIO_NAME,
	.id				= 2,
	.num_resources	= ARRAY_SIZE(fh_gpio2_resources),
	.resource		= fh_gpio2_resources,
	.dev			= {
		.platform_data = &fh_gpio2_chip,
	},
};

static struct platform_device fh_gpio3_device = {
	.name			= GPIO_NAME,
	.id				= 3,
	.num_resources	= ARRAY_SIZE(fh_gpio3_resources),
	.resource		= fh_gpio3_resources,
	.dev			= {
		.platform_data = &fh_gpio3_chip,
	},
};

static struct platform_device fh_gpio4_device = {
	.name			= GPIO_NAME,
	.id				= 4,
	.num_resources	= ARRAY_SIZE(fh_gpio4_resources),
	.resource		= fh_gpio4_resources,
	.dev			= {
		.platform_data = &fh_gpio4_chip,
	},
};

static struct platform_device fh_gpio5_device = {
	.name			= GPIO_NAME,
	.id				= 5,
	.num_resources	= ARRAY_SIZE(fh_gpio5_resources),
	.resource		= fh_gpio5_resources,
	.dev			= {
		.platform_data = &fh_gpio5_chip,
	},
};

static struct platform_device fh_gpio6_device = {
	.name			= GPIO_NAME,
	.id				= 6,
	.num_resources	= ARRAY_SIZE(fh_gpio6_resources),
	.resource		= fh_gpio6_resources,
	.dev			= {
		.platform_data = &fh_gpio6_chip,
	},
};



static struct resource fh_mc_dma_resources[] = {
	{
		.start          = (DMA0_REG_BASE),
		.end            = (DMA0_REG_BASE) + SZ_16K - 1,
		.flags          = IORESOURCE_MEM,
	},
	{
		.start          = DMA0_IRQ,
		.end            = DMA0_IRQ,
		.flags          = IORESOURCE_IRQ,
	},
};

struct fh_mc_dma_platform_data mc_dma_plat_data = {
	.chan_priority  = CHAN_PRIORITY_ASCENDING,
	.clk_name       = "ahb_clk",
	.flag = FORCE_USER_SETTTING_CHANNO,
	.chan_no = 20,
};

static struct platform_device fh_mc_dma_device = {
	.name = "fh_mc_dmac",
	.id = 0,
	.num_resources = ARRAY_SIZE(fh_mc_dma_resources),
	.resource = fh_mc_dma_resources,
	.dev = {
		.platform_data = &mc_dma_plat_data,
	},
};


static struct resource fh_i2s_resources[] = {
	{
		.start		= I2S_REG_BASE,
		.end		= I2S_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= I2S0_IRQ,
		.end		= I2S0_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct fh_i2s_platform_data fh_i2s_data = {
	.dma_capture_channel = 4,
	.dma_playback_channel = 5,
	.dma_master = 0,
	.dma_rx_hs_num = 17,
	.dma_tx_hs_num = 16,
	.clk = "i2s_apb_clk",
};

static struct platform_device fh_i2s_device = {
	.name			= "fh_audio",
	.id			= 0,
	.num_resources		= ARRAY_SIZE(fh_i2s_resources),
	.resource		= fh_i2s_resources,
	.dev			= {
		.platform_data = &fh_i2s_data,
	},
};

static struct platform_device fh_pinctrl_device = {
	.name			= "fh_pinctrl",
	.id			= 0,
};

static struct platform_device fh_i2c0_device = {
	.name			= "fh_i2c",
	.id			= 0,
	.num_resources		= ARRAY_SIZE(fh_i2c_resources_0),
	.resource		= fh_i2c_resources_0,
};

static struct platform_device fh_i2c1_device = {
	.name			= "fh_i2c",
	.id			= 1,
	.num_resources		= ARRAY_SIZE(fh_i2c_resources_1),
	.resource		= fh_i2c_resources_1,
};
static struct fh_rtc_plat_data rtc_plat_data = {
	.lut_cof = 62,
	.lut_offset = 0xfc,
	.tsensor_cp_default_out = 0xa44,
	.clk_name = "rtc_gate",
};

static struct platform_device fh_rtc_device = {
	.name			= "fh_rtc",
	.id			= 0,
	.num_resources		= ARRAY_SIZE(fh_rtc_resources),
	.resource		= fh_rtc_resources,
	.dev.platform_data	= &rtc_plat_data,
};

/*
 *#ifdef CONFIG_HW_RANDOM_FH
 *static struct platform_device fh_rng_device = {
 *	.name			= "fh-rng",
 *	.id				= 0,
 *	.num_resources	= ARRAY_SIZE(fh_rng_resources),
 *	.resource		= fh_rng_resources,
 *	.dev			= {
 *		.platform_data = NULL,
 *	}
 *};
 *#endif
 */

static char *dr_mode_customize(void)
{
	/**
	 * Add your code here to select either host mode or device mode
	 * according gpio input value.
	 * It's a binary choice, and very different to otg mode.
	 * Example: usb dual role play is selected by gpio input.
	 * if (gpio_read == high)
	 *     return "host";
	 * else if (gpio_read == low)
	 *     return "peripheral";
	 * else
	 */
	return "peripheral";
}

static struct fh_usb_platform_data fh_usb_data = {
	.dr_mode  = "host",
	.vbus_pwren = 47,
	.dr_mode_cust = dr_mode_customize,
};

struct platform_device fh_usb_device = {
	.name			= "fh_usb",
	.id				= 0,
	.num_resources	= ARRAY_SIZE(fh_usb_resources),
	.resource		= fh_usb_resources,
	.dev			= {
		.platform_data = &fh_usb_data,
	}
};

static struct fh_pwm_data pwm_data = {
	.npwm = 4,
};

static struct platform_device fh_pwm_device = {
	.name			= "fh_pwm",
	.id				= 0,
	.num_resources	= ARRAY_SIZE(fh_pwm_resources),
	.resource		= fh_pwm_resources,
	.dev			= {
		.platform_data = &pwm_data,
	},
};

struct platform_device fh_wdt0_device = {
	.name			= "fh_wdtv2",
	.id				= 0,
	.num_resources	= ARRAY_SIZE(fh_wdt0_resources),
	.resource		= fh_wdt0_resources,
	.dev			= {
		.platform_data = NULL,
	}
};

#ifdef CONFIG_FH_TSENSOR
struct platform_device fh_tsensor_device = {
	.name			= "fh_tsensor",
	.id				= 0,
};
#endif


#define FH_SPI0_CS0	(5)
#define FH_SPI1_CS0	(20)

#define SPI0_FIFO_DEPTH				(128)
#define SPI0_CLK_IN					(100000000)
#define SPI0_MAX_SLAVE_NO			(1)
#define SPI0_DMA_RX_CHANNEL			(0)
#define SPI0_DMA_TX_CHANNEL			(1)

#define SPI1_FIFO_DEPTH				(64)
#define SPI1_CLK_IN					(100000000)
#define SPI1_MAX_SLAVE_NO			(1)
#define SPI1_DMA_RX_CHANNEL			(2)
#define SPI1_DMA_TX_CHANNEL			(3)

/* SPI_TRANSFER_USE_DMA */
static struct fh_spi_platform_data fh_spi0_data = {
	.bus_no = 0,
	.apb_clock_in = SPI0_CLK_IN,
	.clock_source = {SPI0_CLK_IN},
	.clock_source_num = 1,
	.slave_max_num = SPI0_MAX_SLAVE_NO,
	.cs_data[0].GPIO_Pin = FH_SPI0_CS0,
	.cs_data[0].name = "spi0_cs0",
	.clk_name = "spi0_clk",
	.dma_transfer_enable = SPI_TRANSFER_USE_DMA,
	.rx_dma_channel = SPI0_DMA_RX_CHANNEL,
	.tx_dma_channel = SPI0_DMA_TX_CHANNEL,
	.rx_handshake_num = 12,
	.tx_handshake_num = 13,
	/*dma use inc mode could move data by burst mode...*/
	/*or move data use single mode with low efficient*/
	.ctl_wire_support = ONE_WIRE_SUPPORT | DUAL_WIRE_SUPPORT |QUAD_WIRE_SUPPORT|
	MULTI_WIRE_SUPPORT,
};

static struct fh_spi_platform_data fh_spi1_data = {
	.bus_no = 1,
	.apb_clock_in = SPI1_CLK_IN,
	.clock_source = {SPI1_CLK_IN},
	.clock_source_num = 1,
	.slave_max_num = SPI1_MAX_SLAVE_NO,
	.cs_data[0].GPIO_Pin = FH_SPI1_CS0,
	.cs_data[0].name = "spi1_cs0",
	.clk_name = "spi1_clk",
	.dma_transfer_enable = SPI_TRANSFER_USE_DMA,
	.rx_dma_channel = SPI1_DMA_RX_CHANNEL,
	.tx_dma_channel = SPI1_DMA_TX_CHANNEL,
	.rx_handshake_num = 10,
	.tx_handshake_num = 11,
	.ctl_wire_support = 0,
};

static struct platform_device fh_spi0_device = {
	.name			= "fh_spi",
	.id			= 0,
	.num_resources		= ARRAY_SIZE(fh_spi0_resources),
	.resource		= fh_spi0_resources,
	.dev			= {
		.platform_data = &fh_spi0_data,
	},
};

static struct platform_device fh_spi1_device = {
	.name			= "fh_spi",
	.id			= 1,
	.num_resources		= ARRAY_SIZE(fh_spi1_resources),
	.resource		= fh_spi1_resources,
	.dev			= {
		.platform_data = &fh_spi1_data,
	},
};

#ifdef CONFIG_FH_STEPMOTOR
static struct platform_device fh_stepmotor_device0 = {
	.name			= "fh_stepmotor",
	.id			= 0,
	.num_resources		= ARRAY_SIZE(fh_stepmotor_resources0),
	.resource		= fh_stepmotor_resources0,
	.dev			= {
	.platform_data = NULL,
	},
};
static struct platform_device fh_stepmotor_device1 = {
	.name			= "fh_stepmotor",
	.id			= 1,
	.num_resources		= ARRAY_SIZE(fh_stepmotor_resources1),
	.resource		= fh_stepmotor_resources1,
	.dev			= {
	.platform_data = NULL,
	},
};
#endif

#ifdef CONFIG_FH_RSA
static struct platform_device fh_rsa_device = {
	.name			= "fh_rsa",
	.id				= 1,
	.num_resources	= ARRAY_SIZE(fh_rsa_resources),
	.resource		= fh_rsa_resources,
	.dev			= {
		.platform_data = NULL,
	},
};
#endif

static struct mtd_partition fh_sf_parts[] = {
	{
		/* head & Ramboot */
		.name		= "bootstrap",
		.offset		= 0,
		.size		= SZ_128K,
		.mask_flags	= MTD_WRITEABLE, /* force read-only */
	}, {
		/* Ramboot & U-Boot environment */
		.name		= "uboot-env",
		.offset		= MTDPART_OFS_APPEND,
		.size		= SZ_128K,
		.mask_flags	= MTD_WRITEABLE, /* force read-only */
	}, {
		/* U-Boot */
		.name		= "uboot",
		.offset		= MTDPART_OFS_APPEND,
		.size		= SZ_512K,
		.mask_flags	= MTD_WRITEABLE, /* force read-only */
	}, {
		.name		= "kernel",
		.offset		= MTDPART_OFS_APPEND,
		.size		= 3*SZ_1M,
		.mask_flags	= 0,
	}, {
		.name		= "rootfs",
		.offset		= MTDPART_OFS_APPEND,
		.size		= SZ_8M,
		.mask_flags	= 0,
	}, {
		.name		= "app",
		.offset		= MTDPART_OFS_APPEND,
		.size		= MTDPART_SIZ_FULL,
		.mask_flags	= 0,
	}
	/* mtdparts=
	* spi_flash:256k(bootstrap),
	* 64k(u-boot-env),
	* 192k(u-boot),4M(kernel),
	* 8M(rootfs),
	* -(app) */
	/* two blocks with bad block table (and mirror) at the end */
};

#ifdef CONFIG_MTD_SPI_NAND
static struct mtd_partition fh_sf_nand_parts[] = {
	{
		/* head & Ramboot */
		.name		= "ddr-parameter",
		.offset		= 0,
		.size		= SZ_128K,
		.mask_flags	= MTD_WRITEABLE, /* force read-only */
	}, {
		.name		= "uboot-env",
		.offset		= MTDPART_OFS_APPEND,
		.size		= SZ_128K,
		.mask_flags	= MTD_WRITEABLE,
	}, {
		.name		= "ramboot",
		.offset		= MTDPART_OFS_APPEND,
		.size		= SZ_64K,
		.mask_flags	= MTD_WRITEABLE,
	}, {
		.name		= "uboot",
		.offset		= MTDPART_OFS_APPEND,
		.size		= 704 * SZ_1K,
		.mask_flags	= MTD_WRITEABLE,
	}, {
		.name		= "logo",
		.offset		= MTDPART_OFS_APPEND,
		.size		= SZ_1M,
		.mask_flags	= 0,
	}, {
		.name		= "padding",
		.offset		= MTDPART_OFS_APPEND,
		.size		= SZ_1M,
		.mask_flags	= 0,
	}, {
		.name		= "misc",
		.offset		= MTDPART_OFS_APPEND,
		.size		= SZ_1M,
		.mask_flags	= 0,
	}, {
		.name		= "recovery",
		.offset		= MTDPART_OFS_APPEND,
		.size		= 12*SZ_1M,
		.mask_flags	= 0,
	}, {
		.name		= "boot",
		.offset		= MTDPART_OFS_APPEND,
		.size		= 12*SZ_1M,
		.mask_flags	= 0,
	}, {
		.name		= "res",
		.offset		= MTDPART_OFS_APPEND,
		.size		= 10*SZ_1M,
		.mask_flags	= 0,
	}, {
		.name		= "qua",
		.offset		= MTDPART_OFS_APPEND,
		.size		= 60*SZ_1M,
		.mask_flags	= 0,
	}, {
		.name		= "app",
		.offset		= MTDPART_OFS_APPEND,
		.size		= SZ_16M,
		.mask_flags	= 0,
	}, {
		.name		= "data",
		.offset		= MTDPART_OFS_APPEND,
		.size		= 6*SZ_1M,
		.mask_flags	= 0,
	}, {
		.name		= "reserved",
		.offset		= MTDPART_OFS_APPEND,
		.size		= MTDPART_SIZ_FULL,
		.mask_flags	= 0,
	}
	/* mtdparts=
	 * spi0.0:64k(bootstrap),
	 * 64k(u-boot-env),
	 * 192k(u-boot),
	 * 4M(kernel),
	 * 8M(rootfs),
	 * -(app)
	 * two blocks with bad block table (and mirror) at the end
	 */
};
#endif

static struct flash_platform_data fh_flash_platform_data  = {
	.name		= "spi_flash",
	.parts		= fh_sf_parts,
	.nr_parts	= ARRAY_SIZE(fh_sf_parts),
};

#ifdef CONFIG_MTD_SPI_NAND
static struct flash_platform_data fh_nandflash_platform_data  = {
	.name		= "spi_nandflash",
	.parts		= fh_sf_nand_parts,
	.nr_parts	= ARRAY_SIZE(fh_sf_nand_parts),
};
#endif

static struct spi_board_info fh_spi_devices[] = {
#ifdef CONFIG_MTD_SPI_NAND
	{
		.modalias		= "spi-nand",
		.bus_num		= 0,
		.chip_select	= 0,
		.max_speed_hz	= 50000000,
		.mode			= SPI_MODE_3 | SPI_RX_QUAD,
		.platform_data	 = &fh_nandflash_platform_data,
	},
#endif
#if 0
	{
		.modalias        = "m25p80",
		.bus_num         = 0,
		.chip_select     = 0,
		/* multi wire should adapt spi para 'ctl_wire_support'*/
		.mode            = SPI_MODE_3 | SPI_RX_DUAL,
		.max_speed_hz    = 50000000,
		.platform_data   = &fh_flash_platform_data,
	},
#endif
};

#ifdef CONFIG_MOL_PERF
static struct resource fh_mc_perf_resources[] = {
	{
		.start		= PERF_MON0_REG_BASE,
		.end		= PERF_MON0_REG_BASE + SZ_4K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= DMC_PERF_MON_IRQ,
		.end		= DMC_PERF_MON_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct platform_device fh_mc_perf_device = {
	.name				= "fh-mc-perfmon",
	.id					= 0,
	.num_resources		= ARRAY_SIZE(fh_mc_perf_resources),
	.resource			= fh_mc_perf_resources,
	.dev = {
		.platform_data = (void *)3, /* channel num */
	}
};
#endif


static struct resource mol_efuse_resources[] = {
	{
		.start = EFUSE_REG_BASE,
		.end = EFUSE_REG_BASE + SZ_16K - 1,
		.flags = IORESOURCE_MEM,
	},
};

#ifdef CONFIG_MOL_EFUSE_TEE
static int efuse_uuid[11] = {0x796ad1ff, 0x5565, 0x4141,
		0x9a, 0x1c, 0x29, 0x00, 0x20, 0xaa, 0x9f, 0x16};
#endif

struct mol_efuse_platform_data mol_efuse_plat_data = {
	.efuse_support_flag = CRYPTO_CPU_SET_KEY |
	CRYPTO_EX_MEM_SET_KEY | CRYPTO_EX_MEM_SWITCH_KEY |
	CRYPTO_EX_MEM_4_ENTRY_1_KEY | CRYPTO_EX_MEM_INDEP_POWER,
#ifdef CONFIG_MOL_EFUSE_TEE
	.optee_uuid = efuse_uuid,
#endif
	.block_version = EFUSE_16BLK_VER,
};


static struct platform_device mol_efuse_device = {
	.name = "fh_efuse",
	.id = 0,
	.num_resources = ARRAY_SIZE(mol_efuse_resources),
	.resource = mol_efuse_resources,
	.dev = {
		.platform_data = &mol_efuse_plat_data,
	},
};


static struct resource fh_cesa_resources[] = {
	{
		.start		= AES_REG_BASE,
		.end		= AES_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= AES_IRQ,
		.end		= AES_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

#ifdef CONFIG_CRYPTO_DEV_FH_AES_TEE
static int aes_uuid[11] = {0xdd00d7bd, 0xe9e3, 0x4dcb,
		0xad, 0xbc, 0xda, 0x54, 0xa7, 0x1b, 0x9b, 0x65};
#endif

static struct fh_cesa_platform_data fh_cesa_data = {
	.ext_dma_enable = CESA_USE_EXT_DMA,
	.ext_dma_rx_handshake = 8,
	.ext_dma_tx_handshake = 9,
	.phy_reg_base = AES_REG_BASE,
};

static struct platform_device fh_cesa_device = {
	.name			= "fh_cesa",
	.id			= 0,
	.num_resources		= ARRAY_SIZE(fh_cesa_resources),
	.resource		= fh_cesa_resources,
	.dev			= {
	.coherent_dma_mask	= DMA_BIT_MASK(32),
#ifdef CONFIG_CRYPTO_DEV_FH_AES_TEE
	.platform_data = aes_uuid,
#else
	.platform_data = &fh_cesa_data,
#endif
	},
};

static void plat_suspend(void)
{
	lp_plat_suspend();
	/* sync to arc */
	SET_REG(REG_PMU_ECO0, 0xdeadbeef);
	dsb();
}

static void plat_resume(void)
{
	lp_plat_resume();
	dsb();
}

static struct fh_pm_plat fh_pm_platdata = {
	.rambase = RAM_BASE,
	.addr1 = DDR_CTRL_REG_BASE,
	.addr2 = CEN_GLB_APB_REG_BASE,
	.suspend_fn = plat_suspend,
	.resume_fn = plat_resume,
};

static struct platform_device fh_pm_device = {
	.name				= "fh-pm",
	.num_resources		= 0,
	.dev	= {
		.platform_data = &fh_pm_platdata,
	},
};

static unsigned int bl_levels[] = {
		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
		11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
		21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
		31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
		41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
		51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
		61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
		71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
		81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
		91, 92, 93, 94, 95, 96, 97, 98, 99, 100
};

static struct platform_pwm_backlight_data qm_bl_platdata = {
	.pwm_id = 0,
	.max_brightness = ARRAY_SIZE(bl_levels) - 1,
	.dft_brightness = 90,
	.levels = bl_levels,
	.pwm_period_ns = 10000, //100kHz
	.lth_brightness = 10,
};

static struct platform_device qm_bl_device = {
	.name			= "pwm-backlight",
	.num_resources		= 0,
	.dev	= {
		.platform_data = &qm_bl_platdata,
	},
};

static struct platform_device *qm102v_devices[] __initdata = {
	&fh_uart0_device,
#ifndef CONFIG_FH_AOV_TEST
	&fh_uart1_device,
#endif
	&fh_uart2_device,
	&fh_pinctrl_device,
	//&fh_gmac_qos_0_device,
	&fh_gpio0_device,
	&fh_gpio1_device,
	&fh_gpio2_device,
	&fh_gpio3_device,
	&fh_gpio4_device,
	&fh_gpio5_device,
	&fh_gpio6_device,
#ifndef CONFIG_FH_AOV_TEST
	//&fh_i2c0_device,
#endif
	//&fh_i2c1_device,
//	&fh_rtc_device,
#ifdef CONFIG_HW_RANDOM_FH
	&fh_rng_device,
#endif
	//&fh_sd0_device,
	&fh_sd1_device,
	//&fh_mshc_device,
	&fh_mc_dma_device,
	&fh_sadc_device,
	&fh_cesa_device,
	&mol_efuse_device,
	&fh_spi0_device,
	&fh_spi1_device,
	&fh_i2s_device,
	&fh_pwm_device,
	&fh_wdt0_device,
	&fh_usb_device,
#ifdef CONFIG_USB_DWC3_HCD1_ENABLE
	&fh_usb0_device,
#endif
#ifdef CONFIG_USB_DWC3_HCD2_ENABLE
	&fh_usb1_device,
#endif
#ifdef CONFIG_FH_TSENSOR
	&fh_tsensor_device,
#endif
#ifdef CONFIG_MOL_PERF
	&fh_mc_perf_device,
#endif
#ifdef CONFIG_FH_RSA
	&fh_rsa_device,
#endif
#ifdef CONFIG_MOL_HASH
	//&fh_hash_device,
#endif
#ifdef CONFIG_FH_STEPMOTOR
	&fh_stepmotor_device0,
	&fh_stepmotor_device1,
#endif
#ifdef CONFIG_PM
	&fh_pm_device,
#endif
	&qm_bl_device,
};

extern void early_print(const char *str, ...);

static void __init fh_console_pre_init(struct fh_platform_uart *plat, int num)
{
	int idx = 0;

	for (; idx < num; idx++) {
		struct uart_port *port;

		port            = &fh_serial_ports[idx];
		port->mapbase   = plat[idx].mapbase;
		port->fifosize  = plat[idx].fifo_size;
		port->uartclk   = plat[idx].uartclk;
		port->flags      = plat[idx].flags;

		switch (idx) {
		case 0:
			port->membase = (unsigned char *)VA_UART0_REG_BASE;
			break;
		case 1:
			port->membase = (unsigned char *)VA_UART1_REG_BASE;
			break;
		case 2:
			port->membase = (unsigned char *)VA_UART2_REG_BASE;
			break;
		case 3:
			port->membase = (unsigned char *)VA_UART3_REG_BASE;
			break;
		case 4:
			port->membase = (unsigned char *)VA_UART4_REG_BASE;
			break;
		case 5:
			port->membase = (unsigned char *)VA_UART5_REG_BASE;
			break;
		default:
			break;
		}
	}
}

static void __init qm102v_map_io(void)
{
	iotable_init(qm102v_io_desc, ARRAY_SIZE(qm102v_io_desc));
	/* enable 33bit address space */
	//fh_pmu_set_reg(REG_CPU_ADDR_MSB_SEL, 0xc);

	fh_console_pre_init(fh_uart_platform_data,
			ARRAY_SIZE(fh_uart_platform_data));
}


static __init void qm102v_board_init(void)
{
	platform_add_devices(qm102v_devices,
			ARRAY_SIZE(qm102v_devices));
	spi_register_board_info(fh_spi_devices, ARRAY_SIZE(fh_spi_devices));
}
void  __init fh_timer_init_no_of(unsigned int iovbase,
	unsigned int irqno);

static void __init qm102v_init_early(void)
{
	//fh_pmu_init();
	/* Configure DMA */
	//fh_pmu_set_dma_sel_low(0);
	//fh_pmu_set_dma_sel_high(0);
	//fh_pmu_set_dma0_axcache(0);
	//fh_pmu_set_dma1_axcache(0);
	//mol_pmu_set_efuse_lock_blk(1 << 24);
#ifdef CONFIG_SPI_FH_SLAVE
	//fh_pmu_spi_slave_enable(1);
#else
	//fh_pmu_spi_slave_enable(0);
#endif
	fh_pinctrl_init(VA_CEN_PIN_REG_BASE + 0x8);

//	fh_pmu_set_reg(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x178,
//	0x00108a01);
//	fh_pmu_set_reg(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x17c,
//	0x001fffff);
//	fh_pmu_set_reg_m(SYS_REG_P2V_OFF(VDU_SYS_PIN_REG_BASE) + 0x90,
//	4 << 16, 7 << 16);
}

static void qm102v_restart
				(enum reboot_mode mode, const char *cmd)
{
	fh_pmu_restart();
}
static void __init fh_gic_no_of_init(void)
{
	void *p_gicd = ioremap(GICD_REG_BASE, SZ_16K);
	void *p_gicc = ioremap(GICC_REG_BASE, SZ_16K);

	gic_init(0, -1, p_gicd, p_gicc);
}

int  arch_timer_noof_init(u32 freq,
	u32 ppilist[4], int alwayson, int suspendstop);
static void  __init init_arch_timer_noof(void)
{
	/* arm cortexa7 standard arch-timer ppi id */
	u32 ppilist[4] = {13+16, 14+16, 11+16, 10+16};
	struct clk *cpu_clk;
	unsigned long rate;

	/* arch timer enable */
//	fh_pmu_set_reg_m(REG_CPU_CORE_CTRL, BIT(3), BIT(3));
	fh_clk_init();

//	cpu_clk = clk_get(NULL, "cpu_clk");
//	if (IS_ERR(cpu_clk)) {
//		pr_err("get cpu_clk err: %ld\n", PTR_ERR(cpu_clk));
//		return;
//	}
//	rate = clk_get_rate(cpu_clk);
	rate = 24000000;
	arch_timer_noof_init(rate, ppilist, 0, 0);
}


MACHINE_START(QM102V, "QM102V")
	.atag_offset	= 0x100,
	.map_io		= qm102v_map_io,
	.init_irq	= fh_gic_no_of_init,
	.init_time	= init_arch_timer_noof,
	.init_machine	= qm102v_board_init,
	.init_early	= qm102v_init_early,
	.restart	= qm102v_restart,
#ifdef CONFIG_SMP
	.smp_init = fh_smp_init,
#endif
MACHINE_END



